package handlers

import (
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"qimo_work/config"
	"qimo_work/models"
	"qimo_work/repositories"
	"qimo_work/utils"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

func UploadAttachment(c *gin.Context) {
	// 获取文件
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(400, gin.H{"error": "获取文件失败"})
		return
	}

	// 校验文件类型
	allowedTypes := []string{"image/jpeg", "image/png", "application/pdf"}
	isValid := false
	for _, allowedType := range allowedTypes {
		if file.Header.Get("Content-Type") == allowedType {
			isValid = true
			break
		}
	}
	if !isValid {
		c.JSON(400, gin.H{"error": "文件格式不支持，仅支持 JPG, PNG 或 PDF"})
		return
	}

	// 限制文件大小，最大 5MB
	if file.Size > 5*1024*1024 {
		c.JSON(400, gin.H{"error": "文件不能超过 5MB"})
		return
	}

	// 生成文件存储路径
	ext := filepath.Ext(file.Filename) // 获取文件扩展名
	newFilename := uuid.New().String() + ext
	savePath := filepath.Join("uploads", newFilename)

	// 保存文件到服务器
	if err := c.SaveUploadedFile(file, savePath); err != nil {
		c.JSON(500, gin.H{"error": "保存文件失败", "details": err.Error()})
		return
	}

	// 返回文件的 URL
	fileURL := fmt.Sprintf("http://localhost:9090/uploads/%s", newFilename)
	c.JSON(200, gin.H{"url": fileURL, "name": file.Filename})
}

// 删除文件的接口
func DeleteAttachment(c *gin.Context) {
	// 获取文件名
	filename := c.Param("filename")
	if filename == "" {
		c.JSON(400, gin.H{"error": "文件名不能为空"})
		return
	}

	// 验证用户权限
	token := c.GetHeader("Authorization")
	if token == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "未提供认证令牌"})
		return
	}

	claims, err := utils.ValidateJWT(token)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "无效或过期的令牌"})
		return
	}

	// 构建文件路径
	filePath := filepath.Join("uploads", filename)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		c.JSON(404, gin.H{"error": "文件不存在"})
		return
	}

	// 检查是否是临时上传的附件
	if attachments, ok := tempAttachments[token]; ok {
		for i, attachment := range attachments {
			if attachment.FilePath == fmt.Sprintf("http://localhost:9090/uploads/%s", filename) {
				// 从临时存储中删除
				tempAttachments[token] = append(tempAttachments[token][:i], tempAttachments[token][i+1:]...)
				// 删除物理文件
				if err := os.Remove(filePath); err != nil {
					c.JSON(500, gin.H{"error": "删除文件失败", "details": err.Error()})
					return
				}
				c.JSON(200, gin.H{"message": "文件删除成功"})
				return
			}
		}
	}

	// 如果不是临时上传的附件，则从数据库中删除
	var attachment models.Attachment
	if err := config.DB.Where("file_path LIKE ?", "%"+filename).First(&attachment).Error; err != nil {
		// 如果数据库中没有记录，直接删除文件
		if err := os.Remove(filePath); err != nil {
			c.JSON(500, gin.H{"error": "删除文件失败", "details": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "文件删除成功"})
		return
	}

	// 验证文件是否属于当前用户
	if attachment.UserID != uint(claims.UserID) {
		c.JSON(http.StatusForbidden, gin.H{"error": "您没有权限删除此文件"})
		return
	}

	// 从数据库中删除附件记录
	if err := config.DB.Delete(&attachment).Error; err != nil {
		c.JSON(500, gin.H{"error": "删除数据库记录失败", "details": err.Error()})
		return
	}

	// 删除文件
	if err := os.Remove(filePath); err != nil {
		c.JSON(500, gin.H{"error": "删除文件失败", "details": err.Error()})
		return
	}

	// 返回成功消息
	c.JSON(200, gin.H{"message": "文件删除成功"})
}

// 临时存储上传的附件信息
var tempAttachments = make(map[string][]models.Attachment)

func UploadMultipleAttachments(c *gin.Context) {
	// 获取表单中的多文件
	form, err := c.MultipartForm()
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "获取文件失败"})
		return
	}

	files := form.File["files"] // 表单中文件的字段名为 "files"
	if len(files) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "未上传任何文件"})
		return
	}

	// 获取用户ID
	token := c.GetHeader("Authorization")
	if token == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization token is missing"})
		return
	}

	claims, err := utils.ValidateJWT(token)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
		return
	}
	userID := uint(claims.UserID)

	// 获取文章ID（可选）
	postIDStr := c.PostForm("post_id")
	postID, _ := strconv.Atoi(postIDStr)

	// 保存所有附件信息
	var attachmentURLs []string
	for _, file := range files {
		// 校验文件类型和大小
		if err := validateFile(file); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// 保存文件到服务器
		fileURL, err := saveFile(file)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败", "details": err.Error()})
			return
		}

		// 将附件信息暂存到内存中
		attachment := models.Attachment{
			FileName: file.Filename,
			FilePath: fileURL,
			FileType: file.Header.Get("Content-Type"),
			FileSize: file.Size,
			PostID:   uint(postID),
			UserID:   userID,
		}
		tempAttachments[token] = append(tempAttachments[token], attachment)

		attachmentURLs = append(attachmentURLs, fileURL)
	}

	// 返回所有附件的URL
	c.JSON(http.StatusOK, gin.H{"urls": attachmentURLs})
}

// 在发布文章时，将临时存储的附件信息存入数据库
func SaveAttachmentsToDB(token string, postID uint) error {
	if attachments, ok := tempAttachments[token]; ok {
		for _, attachment := range attachments {
			attachment.PostID = postID
			if err := repositories.CreateAttachment(attachment); err != nil {
				return err
			}
		}
		delete(tempAttachments, token)
	}
	return nil
}

// validateFile 校验文件类型和大小
func validateFile(file *multipart.FileHeader) error {
	// 校验文件类型
	allowedTypes := []string{"image/jpeg", "image/png", "application/pdf"}
	isValid := false
	for _, allowedType := range allowedTypes {
		if file.Header.Get("Content-Type") == allowedType {
			isValid = true
			break
		}
	}
	if !isValid {
		return fmt.Errorf("文件格式不支持，仅支持 JPG, PNG 或 PDF")
	}

	// 校验文件大小
	if file.Size > 5*1024*1024 { // 5MB
		return fmt.Errorf("文件不能超过 5MB")
	}

	return nil
}

// saveFile 保存文件到服务器并返回文件URL
func saveFile(file *multipart.FileHeader) (string, error) {
	// 生成文件存储路径
	ext := filepath.Ext(file.Filename)                // 获取文件扩展名
	newFilename := uuid.New().String() + ext          // 生成唯一文件名
	savePath := filepath.Join("uploads", newFilename) // 构建完整保存路径

	// 确保上传目录存在
	if err := os.MkdirAll("uploads", os.ModePerm); err != nil {
		return "", fmt.Errorf("创建上传目录失败: %v", err)
	}

	// 打开上传的文件
	src, err := file.Open()
	if err != nil {
		return "", fmt.Errorf("打开文件失败: %v", err)
	}
	defer src.Close() // 确保文件关闭

	// 创建目标文件
	dst, err := os.Create(savePath)
	if err != nil {
		return "", fmt.Errorf("创建目标文件失败: %v", err)
	}
	defer dst.Close() // 确保文件关闭

	// 将上传的文件内容复制到目标文件
	if _, err := io.Copy(dst, src); err != nil {
		return "", fmt.Errorf("保存文件失败: %v", err)
	}

	// 返回文件URL
	return fmt.Sprintf("http://localhost:9090/uploads/%s", newFilename), nil
}

// 查询文章的所有附件
func GetAttachmentsByPostID(c *gin.Context) {
	// 获取文章 ID
	postID := c.Param("post_id")
	if postID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "文章 ID 不能为空"})
		return
	}

	// 查询附件
	var attachments []models.Attachment
	if err := config.DB.Where("post_id = ?", postID).Find(&attachments).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询附件失败", "details": err.Error()})
		return
	}

	// 返回附件信息
	c.JSON(http.StatusOK, gin.H{"data": attachments})
}
